#include "HIDPS2conv_ms.h"

HIDPS2conv_MS _HIDPS2conv_MS;

PS2_Client_MS *HIDPS2conv_MS::_PS2Client = nullptr;

void HIDPS2conv_MS::init(PS2_Client_MS *pPS2Client) {

    _PS2Client = pPS2Client;
}

void HIDPS2conv_MS::ble_onRecvDataHID(BleServerConnector *pConnector, uint8_t *dataBuf, int nLen) {
    for (int i = 0; i < HID_COUNT; i++) {
        HIDPS2conv_HIDPoint &hidPt = s_hidPoint[i];
        if (hidPt.type == 1 && hidPt.pBleServerConnector == pConnector) {
            _HIDPS2conv_MS.onRecvDataHID(i, dataBuf, nLen);
            break;
        }
    }
}

portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
void HIDPS2conv_MS::onRecvDataHID(int num, uint8_t *dataBuf, int nLen) {

    portENTER_CRITICAL(&mux);  // 进入临界区

    HIDPS2conv::onRecvDataHID(num, dataBuf, nLen);

    HIDPS2conv_HIDPoint hidPt = s_hidPoint[num];
    HID &hid = hidPt.hid;

    int offset = 0;
    uint32_t buf;

    bool dataHasReportID = false;
    if (hid._ReportSize + 1 == nLen) {
        dataHasReportID = true;
        offset = 8;
    } else if (hid._ReportSize != nLen) {
        portEXIT_CRITICAL(&mux);  // 退出临界区
        return;
    }

    for (const auto &item : hid.reportItems) {
        if (dataHasReportID && item.reportId != dataBuf[0]) {
            continue;
        }

        // 只解析Input数据
        if (item.type != 0x80) {
            continue;
        }

        buf = 0;
        bincpy(&buf, dataBuf, item.bitBegin + offset, item.bitSize, 16, nLen << 3);

        if (item.usagePage == 0x09) {
            // Button

            _PS2Client->setKey(item.usage - 1, buf);

        } else if (item.usagePage == 0x01) {
            // 移动
            switch (item.usage) {
            case 0x30: // X
                _PS2Client->nodifyPosition(0, buf);
                break;
            case 0x31: // Y
                _PS2Client->nodifyPosition(1, 0 - buf);
                break;
            case 0x38: // Wheel
                _PS2Client->nodifyPosition(2, 0 - buf);
                break;
            }
        }
    }

    portEXIT_CRITICAL(&mux);  // 退出临界区
    // Serial.printf("dev[%d]:button:%d %d %d %d %d", num, _PS2_MS_INFO.KeyStatusTmp[0], _PS2_MS_INFO.KeyStatusTmp[1], _PS2_MS_INFO.KeyStatusTmp[2], _PS2_MS_INFO.KeyStatusTmp[3], _PS2_MS_INFO.KeyStatusTmp[4]);
    // Serial.printf(", move:%5d  %5d  %5d\n", _PS2_MS_INFO.PositionTmp[0], _PS2_MS_INFO.PositionTmp[1], _PS2_MS_INFO.PositionTmp[2]);
}

void HIDPS2conv_MS::usb_onRecvDataHID(USBClientConnector *pConnector, uint8_t *dataBuf, int nLen) {
    for (int i = 0; i < HID_COUNT; i++) {
        HIDPS2conv_HIDPoint &hidPt = s_hidPoint[i];
        if (hidPt.type == 2 && hidPt.pUSBClientConnector == pConnector) {
            _HIDPS2conv_MS.onRecvDataHID(i, dataBuf, nLen);
            break;
        }
    }
}

bool HIDPS2conv_MS::addHidDevice(BleServerConnector *pConnector) {
    HIDPS2conv_HIDPoint *hidPt = HIDPS2conv::addHidDevice(pConnector);
    if (hidPt) {
        pConnector->setBleServerConnectorCallbacks(this);
        pConnector->setOnRecvData(ble_onRecvDataHID);
        return true;
    }
    return false;
}

bool HIDPS2conv_MS::addHidDevice(USBClientConnector *pConnector) {
    HIDPS2conv_HIDPoint *hidPt = HIDPS2conv::addHidDevice(pConnector);
    if (hidPt) {
        pConnector->setUSBClientConnectorCallbacks(this);
        pConnector->setOnRecvData(usb_onRecvDataHID);
        return true;
    }
    return false;
}